This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

1'use client'; 2 3import { useState, useEffect, useMemo, useCallback } from 'react'; 4import { useRouter, useParams } from 'next/navigation'; 5import { 6 Container, 7 Title, 8 TextInput, 9 Textarea, 10 Button, 11 Stack, 12 Card, 13 Group, 14 Alert, 15 LoadingOverlay, 16} from '@mantine/core'; 17import { getAccessToken } from '@/services/auth'; 18import { ApiClient } from '@/api-client/ApiClient'; 19import type { GetCollectionPageResponse } from '@/api-client/types'; 20 21export default function EditCollectionPage() { 22 const router = useRouter(); 23 const params = useParams(); 24 const collectionId = params.collectionId as string; 25 26 // Memoize API client to prevent recreation on every render 27 const apiClient = useMemo( 28 () => 29 new ApiClient( 30 process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3000', 31 () => getAccessToken(), 32 ), 33 [], 34 ); 35 36 const [collection, setCollection] = 37 useState<GetCollectionPageResponse | null>(null); 38 const [name, setName] = useState(''); 39 const [description, setDescription] = useState(''); 40 const [isLoading, setIsLoading] = useState(true); 41 const [isSaving, setIsSaving] = useState(false); 42 const [error, setError] = useState<string | null>(null); 43 const [success, setSuccess] = useState(false); 44 45 // Memoize the load collection function to prevent recreation 46 const loadCollection = useCallback(async () => { 47 if (!collectionId) return; 48 49 try { 50 setIsLoading(true); 51 setError(null); 52 const response = await apiClient.getCollectionPage(collectionId); 53 setCollection(response); 54 setName(response.name); 55 setDescription(response.description || ''); 56 } catch (err) { 57 setError('Failed to load collection'); 58 console.error('Error loading collection:', err); 59 } finally { 60 setIsLoading(false); 61 } 62 }, [collectionId, apiClient]); 63 64 // Load collection data 65 useEffect(() => { 66 loadCollection(); 67 }, [loadCollection]); 68 69 const handleSave = useCallback(async () => { 70 if (!name.trim()) { 71 setError('Collection name is required'); 72 return; 73 } 74 75 try { 76 setIsSaving(true); 77 setError(null); 78 79 await apiClient.updateCollection({ 80 collectionId, 81 name: name.trim(), 82 description: description.trim() || undefined, 83 }); 84 85 setSuccess(true); 86 87 // Redirect back to collection page after a brief delay 88 setTimeout(() => { 89 router.push(`/collections/${collectionId}`); 90 }, 1500); 91 } catch (err) { 92 setError('Failed to update collection'); 93 console.error('Error updating collection:', err); 94 } finally { 95 setIsSaving(false); 96 } 97 }, [name, description, collectionId, apiClient, router]); 98 99 const handleCancel = useCallback(() => { 100 router.push(`/collections/${collectionId}`); 101 }, [router, collectionId]); 102 103 if (isLoading) { 104 return ( 105 <Container size="md" py="xl"> 106 <LoadingOverlay visible /> 107 </Container> 108 ); 109 } 110 111 if (!collection) { 112 return ( 113 <Container size="md" py="xl"> 114 <Alert color="red" title="Collection not found" /> 115 </Container> 116 ); 117 } 118 119 return ( 120 <Container size="md" py="xl"> 121 <Stack gap="lg"> 122 <Title order={1}>Edit Collection</Title> 123 124 <Card withBorder p="lg"> 125 <Stack gap="md"> 126 {error && <Alert color="red" title={error} />} 127 128 {success && ( 129 <Alert 130 color="green" 131 title="Collection updated successfully! Redirecting..." 132 /> 133 )} 134 135 <TextInput 136 label="Collection Name" 137 placeholder="Enter collection name" 138 value={name} 139 onChange={(event) => setName(event.currentTarget.value)} 140 required 141 error={!name.trim() && error ? 'Name is required' : undefined} 142 /> 143 144 <Textarea 145 label="Description" 146 placeholder="Enter collection description (optional)" 147 value={description} 148 onChange={(event) => setDescription(event.currentTarget.value)} 149 minRows={3} 150 maxRows={6} 151 /> 152 153 <Group justify="flex-end" mt="md"> 154 <Button 155 variant="subtle" 156 onClick={handleCancel} 157 disabled={isSaving} 158 > 159 Cancel 160 </Button> 161 <Button 162 onClick={handleSave} 163 loading={isSaving} 164 disabled={!name.trim() || success} 165 > 166 Save Changes 167 </Button> 168 </Group> 169 </Stack> 170 </Card> 171 </Stack> 172 </Container> 173 ); 174}